package com.df.twod_sync_bakend.game;

import com.alibaba.fastjson2.JSON;
import com.df.twod_sync_bakend.game.entity.InputCommand;
import com.df.twod_sync_bakend.game.entity.PlayerState;
import com.df.twod_sync_bakend.model.Player;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

@Slf4j
public class GameRoom {
    private Integer roomId;
    private Map<String, Player> players = new ConcurrentHashMap<>();
    private Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();

    // 输入队列和游戏状态
    private Map<String, List<InputCommand>> inputQueues = new ConcurrentHashMap<>();
    private GameState currentGameState = new GameState();
    private Long lastUpdateTime = System.currentTimeMillis();
    private Integer tickCount = 0;

    private final float MAX_MOVE_DISTANCE = 5.0f; // 每帧最大移动距离

    // 游戏配置
    private static final float TICK_RATE = 20.0f; // 20 ticks per second
    private static final float TICK_INTERVAL_MS = 1000.0f / TICK_RATE;
    private static final float TICK_INTERVAL_SEC = 1.0f / TICK_RATE;
    private static final float MAX_MOVE_SPEED = 400.0f;
    private static final float MOVE_SPEED = 300.0f;
    private static final float MAP_BOUNDARY = 1000.0f;
    private ScheduledExecutorService gameLoopExecutor;
    public GameRoom(Integer roomId) {
        this.roomId = roomId;
        gameLoopExecutor = Executors.newScheduledThreadPool(1);
        // 20 ticks per second (50ms interval)
        gameLoopExecutor.scheduleAtFixedRate(() -> {
            try {
                update();
            } catch (Exception e) {
                log.error("游戏循环异常", e);
            }
        }, 0, 50, TimeUnit.MILLISECONDS);
    }
    public void stopGameLoop() {
        if (gameLoopExecutor != null) {
            gameLoopExecutor.shutdown();
        }
    }

    public boolean addPlayer(String playerId, Float x, Float y, WebSocketSession session) {
        if(players.containsKey(playerId)){
            return false;
        }
        session.getAttributes().put("uid",playerId);
        players.put(playerId, new Player(playerId, x, y));
        sessions.put(playerId, session);
        return true;

    }

    // 添加移动输入到队列
    public void addMoveInputs(String uid, List<InputCommand> inputs) {
        if (inputs == null || inputs.isEmpty()) {
            return;
        }

        inputQueues.computeIfAbsent(uid, k -> Collections.synchronizedList(new ArrayList<>()));
        List<InputCommand> queue = inputQueues.get(uid);

        // 添加新输入
        queue.addAll(inputs);

        // 限制队列大小防止内存溢出
        if (queue.size() > 60) { // 3秒的输入（20tick * 3）
            queue.subList(0, queue.size() - 60).clear();
        }
    }


    public void sendMsg(String uid,String msgType,Object data){
        Map<String, Object> response = new HashMap<>();
        response.put("type", msgType);
        response.put("code", 0);
        response.put("data", data);
        WebSocketSession session = sessions.get(uid);
        if(session!=null && session.isOpen()){
            try {
                session.sendMessage(new TextMessage(JSON.toJSONString(response)));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void sendFailMsg(String uid,String msgType,Object data){
        sendFailMsg(uid,msgType,-1);
    }
    public void sendFailMsg(String uid,String msgType,Object data,Integer errorCode){
        Map<String, Object> response = new HashMap<>();
        response.put("type", msgType);
        response.put("code", errorCode);
        if(data!=null){
            response.put("data", data);
        }
        WebSocketSession session = sessions.get(uid);
        if(session!=null && session.isOpen()){
            try {
                session.sendMessage(new TextMessage(JSON.toJSONString(response)));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void sendFailMsg(WebSocketSession session,String msgType,Object data){
        sendFailMsg(session,msgType,data,-1);
    }

    public void sendFailMsg(WebSocketSession session,String msgType,Object data,Integer errorCode){
        Map<String, Object> response = new HashMap<>();
        response.put("type", msgType);
        response.put("code", errorCode);
        if(data!=null){
            response.put("data", data);
        }
        if(session!=null && session.isOpen()){
            try {
                session.sendMessage(new TextMessage(JSON.toJSONString(response)));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    private boolean validateMove(MoveMessage moveMsg) {
        Player player = players.get(moveMsg.getPlayerId());
        if (player == null) return false;

        // 检查移动距离是否合法
        float deltaX = moveMsg.getPosX() - player.getPosX();
        float deltaY = moveMsg.getPosY() - player.getPosY();
        float distance = (float) Math.sqrt(deltaX * deltaX + deltaY * deltaY);

        // 考虑网络延迟，允许一定的移动距离
        return distance <= MAX_MOVE_DISTANCE * 3; // 允许3帧的移动
    }

    public void update() {
        long currentTime = System.currentTimeMillis();
        float deltaTime = (currentTime - lastUpdateTime) / 1000.0f;

        // 处理所有移动消息
        processMoveMessages(deltaTime);

        // 更新游戏状态
        updateGameState(currentTime);

        // 广播游戏状态
        broadcastGameState();

        lastUpdateTime = currentTime;
        tickCount++;
    }
    // 处理移动消息
    private void processMoveMessages(float deltaTime) {
        inputQueues.forEach((uid, inputs) -> {
            Player player = players.get(uid);
            if (player == null || inputs.isEmpty()) {
                return;
            }

            // 按序列号排序
            inputs.sort(Comparator.comparingInt(InputCommand::getSequence));

            // 处理连续输入
            processPlayerInputs(player, inputs, deltaTime);
        });
    }
    // 处理玩家输入
    private void processPlayerInputs(Player player, List<InputCommand> inputs, float deltaTime) {
        int lastProcessed = player.getLastProcessedSequence();

        for (InputCommand input : inputs) {
            // 跳过已处理的输入
            if (input.getSequence() <= lastProcessed) {
                continue;
            }

            // 验证输入
            if (!validatePlayerInput(player, input)) {
                log.warn("输入验证失败: uid={}, sequence={}", player.getUid(), input.getSequence());
                continue;
            }

            // 应用输入
            applyPlayerInput(player, input, deltaTime);
            player.setLastProcessedSequence(input.getSequence());
            lastProcessed = input.getSequence();
        }

        // 移除已处理的输入
        inputs.removeIf(input -> input.getSequence() <= player.getLastProcessedSequence());
    }
    // 验证玩家输入
    private boolean validatePlayerInput(Player player, InputCommand input) {
        // 检查序列号连续性（允许一定的丢包）
        if (input.getSequence() > player.getLastProcessedSequence() + 10) {
            log.warn("序列号跳跃过大: current={}, new={}",
                    player.getLastProcessedSequence(), input.getSequence());
            return false;
        }

        // 检查移动速度
        if (input.getDirectionX() != null && input.getDirectionY() != null) {
            float magnitude = (float) Math.sqrt(
                    input.getDirectionX() * input.getDirectionX() +
                            input.getDirectionY() * input.getDirectionY()
            );

            if (magnitude > 1.5f) { // 允许轻微超界
                return false;
            }

            // 计算提议速度
            float proposedSpeedX = input.getDirectionX() * player.getMoveSpeed();
            float proposedSpeedY = input.getDirectionY() * player.getMoveSpeed();
            float proposedSpeed = (float) Math.sqrt(proposedSpeedX * proposedSpeedX + proposedSpeedY * proposedSpeedY);

            if (proposedSpeed > MAX_MOVE_SPEED * 1.2f) {
                return false;
            }
        }

        return true;
    }
    // 应用玩家输入
    private void applyPlayerInput(Player player, InputCommand input, float deltaTime) {
        // 计算速度
        if (input.getDirectionX() != null && input.getDirectionY() != null) {
            player.setVelocityX(input.getDirectionX() * player.getMoveSpeed());
            player.setVelocityY(input.getDirectionY() * player.getMoveSpeed());
        }

        // 更新位置
        float newX = player.getPosX() + player.getVelocityX() * deltaTime;
        float newY = player.getPosY() + player.getVelocityY() * deltaTime;

        // 边界检查
        newX = clamp(newX, -MAP_BOUNDARY, MAP_BOUNDARY);
        newY = clamp(newY, -MAP_BOUNDARY, MAP_BOUNDARY);

        player.setPosX(newX);
        player.setPosY(newY);
        player.setLastActivityTime(System.currentTimeMillis());
    }
    // 边界限制
    private float clamp(float value, float min, float max) {
        return Math.max(min, Math.min(max, value));
    }

    // 更新游戏状态
    private void updateGameState(long currentTime) {
        currentGameState.setTimestamp(currentTime);
        currentGameState.setTickCount(tickCount);

        players.forEach((uid, player) -> {
            PlayerState state = new PlayerState();
            state.setUid(uid);
            state.setPosX(player.getPosX());
            state.setPosY(player.getPosY());
            state.setVelocityX(player.getVelocityX());
            state.setVelocityY(player.getVelocityY());
            state.setRotation(player.getRotation());
            state.setTimestamp(currentTime);
            state.setSequence(player.getLastProcessedSequence());

            currentGameState.getPlayers().put(uid, state);
        });
    }
    // 广播游戏状态
    private void broadcastGameState() {
        if (currentGameState.getPlayers().isEmpty()) {
            return;
        }

        Map<String, Object> broadcastMsg = new HashMap<>();
        broadcastMsg.put("type", "GameState");
        broadcastMsg.put("code", 0);
        broadcastMsg.put("data", currentGameState);

        String messageJson = JSON.toJSONString(broadcastMsg);
        TextMessage textMessage = new TextMessage(messageJson);

        // 广播给所有连接的会话
        sessions.forEach((uid, session) -> {
            if (session != null && session.isOpen()) {
                try {
                    session.sendMessage(textMessage);
                } catch (IOException e) {
                    log.error("广播消息失败: uid={}", uid, e);
                }
            }
        });
    }



    public void removePlayer(String uid) {
        //TODO 广播给其他玩家
//        broadCast(null,);
        players.remove(uid);
    }
    public void broadCast( String msgType,Object data) {
        List<String> uids = players.keySet().stream().toList();
        for (String uid : uids) {
            sendMsg(uid,msgType,data);
        }
    }
    public void broadCast(List<String> uids, String msgType,Object data) {
        if(uids==null){
            uids = players.keySet().stream().toList();
        }
        for (String uid : uids) {
            sendMsg(uid,msgType,data);
        }
    }
    public void broadCastExclude(List<String> uids, String msgType,Object data) {
        List<String> list = players.keySet().stream().toList();
        for (String uid : list) {
            if(!uids.contains(uid)){
                sendMsg(uid,msgType,data);
            }
        }
    }

    public Map<String, Player> getPlayers() {
        return players;
    }
}